#include "DFarm.h"
#include "Debug.h"

//#define HOST_HOST_SPLIT   ","
//#define HOST_PORT_SPLIT   ":"

DFarm::DFarm(DbParam dbParameters, const char *readers, const char *writers, bool debug)
: Farm(dbParameters)
{
        this->debug_ = debug;
	char **hosts = g_strsplit(readers, HOST_HOST_SPLIT, -1);
	int hosts_num =  g_strv_length(hosts);
	for(int i=0; i< hosts_num ; i++ )
	{
		char **hps = g_strsplit(hosts[i], HOST_PORT_SPLIT, -1);
		int  hps_num =  g_strv_length(hps);
                DbHost *db = NULL;
                if(hps_num == 1)
		{
			db = new DbHost();     
			db->dbHost_ = g_strstrip(hps[0]);
			db->dbPort_ = dbParameters.dbPort_;
		}
		else if(hps_num == 2)
		{
			db = new DbHost();     
			db->dbHost_ = g_strstrip(hps[0]);
			db->dbPort_ = atoi(hps[1] );
                }
                else
                {
                   if(debug_)
                      cerr << hosts[i] <<  "'s format is error, can't parser it! "<<endl;
                   abort();
                }
                if(db != NULL)
                {
                   db->deadTime_ = 0;
                   db->dbLive_ = true;
                   readers_.push_back(db);
                } 
		g_strfreev (hps);
	}
	g_strfreev (hosts );

	hosts = g_strsplit(writers, HOST_HOST_SPLIT, -1);
	hosts_num =  g_strv_length(hosts);
	for(int i=0; i< hosts_num ; i++ )
	{
		char **hps = g_strsplit(hosts[i], HOST_PORT_SPLIT, -1);
		int  hps_num =  g_strv_length(hps);
                DbHost *db = NULL;
                if(hps_num == 1)
		{
			db = new DbHost();     
			db->dbHost_ =g_strstrip(hps[0]);
			db->dbPort_ = dbParameters.dbPort_;
		}
		else if(hps_num == 2)
		{
			db = new DbHost();     
			db->dbHost_ = g_strstrip(hps[0]);
			db->dbPort_ = atoi(hps[1] );
                }
                else
                {
                   if(debug_)
                      cerr << hosts[i] <<  " is error! "<<endl;
                   abort();
                }
                if(db != NULL)
                {
                   db->deadTime_ = 0;
                   db->dbLive_ = true;
                   writers_.push_back(db);
                } 
		g_strfreev (hps);
	}
	g_strfreev (hosts );
        rCount_ = 0;
}

MYSQL* DFarm::GetWriter(int idx)
{
#ifdef _THREAD_SAFE
        pthread_mutex_lock(&_lock);
        DEBUG1("+++++++++++++++++++++ pthread_mutex_lock, please sure to use unlock");
#endif

	int size = (int)writers_.size();
	if( idx<0 || idx >= size )
	{
		error_ = "writer's idx is out bounder";
		return NULL;
	}

	DbHost *dh = (DbHost *) writers_[idx];
	MYSQL *c = NULL;
	c = mysql_init(NULL);
        DEBUG5(myDb_.dbUser_.c_str()," : ", myDb_.dbPass_.c_str()," : ", myDb_.dbName_.c_str());
        mysql_options(c, MYSQL_SET_CHARSET_NAME,  myDb_.dbCharset_.c_str());

	if(NULL == mysql_real_connect(c,
				dh->dbHost_.c_str(),
				myDb_.dbUser_.c_str(),
				myDb_.dbPass_.c_str(),
				myDb_.dbName_.c_str(),
				dh->dbPort_, 
				NULL,               /* my_bool compress */
				myDb_.dbTimeOut_))
	{
		ERRO << mysql_error(c) << endl;
		mysql_close(c);
		c = NULL;
		dh->dbLive_ =  false;
		dh->deadTime_ = time(NULL);
		if(debug_)
			cerr<<"Could not connect "<< myDb_.dbName_ <<", "<< dh->dbHost_ << ", " << myDb_.dbUser_ << endl;

	}
	return c;               
}

MYSQL* DFarm::GetReader()
{
#ifdef _THREAD_SAFE
        pthread_mutex_lock(&_lock);
        DEBUG1("+++++++++++++++++++++   pthread_mutex_lock, please sure to use unlock");
#endif
     int size = (int)readers_.size();
     if(size <= 0)
	     return NULL;
     int num = 0;
     MYSQL *c = NULL;
     while(num < size )
     {
        c = getNextReader(num , size);
        if(c != NULL)
           return c;
     } 
     error_ = "can't connection all readers";
     return NULL;
}

MYSQL* DFarm::getNextReader(int &num, int size )
{
       num++;
       rCount_ = rCount_%size; 
       DbHost *dh = (DbHost *) readers_[ rCount_ ++ ];
       if(!dh->dbLive_)	
       {
          long lt = time(NULL);
          if(dh->deadTime_ > lt - 300)
              return NULL;
          dh->dbLive_ = true; 
       } 
       DEBUG5(myDb_.dbUser_.c_str()," : ", myDb_.dbPass_.c_str()," : ", myDb_.dbName_.c_str());

       MYSQL *c = NULL;
       c = mysql_init(NULL);
       mysql_options(c, MYSQL_SET_CHARSET_NAME,  myDb_.dbCharset_.c_str());

       if(NULL == mysql_real_connect(c,
			       dh->dbHost_.c_str(),
			       myDb_.dbUser_.c_str(),
			       myDb_.dbPass_.c_str(),
			       myDb_.dbName_.c_str(),
			       dh->dbPort_,		
			       NULL,    /* my_bool compress */
			       myDb_.dbTimeOut_))
       {
	       ERRO << mysql_error(c) << endl;
	       mysql_close(c);
	       c = NULL;
	       dh->dbLive_ =  false;
	       dh->deadTime_ = time(NULL);
	       if(debug_)
		       cerr<<"Could not connect "<< myDb_.dbName_ <<", "<< dh->dbHost_ << ", " << myDb_.dbUser_ << endl;

       }
       return c;               
}

void DFarm::CloseConnection(MYSQL *c, bool write)      
{
	if(c!= NULL)
	{
		mysql_close(c);
		c = NULL;
	}
#ifdef _THREAD_SAFE
        pthread_mutex_unlock(&_lock);
        DEBUG1("-----------------------      pthread_mutex_unlock");
#endif
}

void DFarm:: closeAll()
{

}

void DFarm:: Print()
{
#ifdef _THREAD_SAFE
        pthread_mutex_lock(&_lock);
        DEBUG1("+++++++++++++++++++++++     pthread_mutex_lock, please sure to use unlock");
#endif

	cout<<"DFarm writers ::"<<endl;
	for (size_t i=0; i < writers_.size(); ++i)
	{      
		DbHost *dh = (DbHost *) writers_[ (int)i ];
		cout<< "w["<< i<<"] ="<< dh->dbHost_.c_str()<< ":" << dh->dbPort_ <<":"<< dh->deadTime_ <<":"<< dh->dbLive_<<endl;

	}

	cout<<"MFarm readers ::"<<endl;
	for (size_t i=0; i < readers_.size(); ++i)
	{      
		DbHost *dh = (DbHost *) readers_[ (int)i ];
		cout<< "r["<< i<<"] = "<< dh->dbHost_.c_str()<< ":" << dh->dbPort_ <<":"<< dh->deadTime_ <<":"<< dh->dbLive_<<endl;

	}
#ifdef _THREAD_SAFE
        pthread_mutex_unlock(&_lock);
        DEBUG1("-----------------------    pthread_mutex_unlock");
#endif

}
